<script setup>
import { ref, computed, reactive, nextTick } from 'vue'
import { ElMessage } from 'element-plus'
import { baseURL } from '@/utils/request' // 导入baseURL

const props = defineProps({
  currentAvatar: {
    type: String,
    default: ''
  },
  defaultAvatar: {
    type: String,
    default: 'https://cube.elemecdn.com/3/7c/3ea6beec64369c2642b92c6726f1epng.png'
  }
})

const emit = defineEmits(['update'])

// 文件输入引用
const fileInputRef = ref(null)
const previewBoxRef = ref(null)
const cropImageRef = ref(null)
const cropFrameRef = ref(null)

// 状态
const avatarFile = ref(null)
const avatarPreview = ref(null)
const croppedPreview = ref(null)

// 裁剪相关状态
const frameSize = ref(180) // 裁剪框初始大小
const framePosition = reactive({ x: 0, y: 0 })
const dragInfo = reactive({ 
  isDragging: false,
  isResizing: false,
  startX: 0,
  startY: 0,
  startSize: 0,
  startPosX: 0,
  startPosY: 0
})

// 计算裁剪框样式
const cropFrameStyle = computed(() => {
  return {
    width: `${frameSize.value}px`,
    height: `${frameSize.value}px`,
    left: `${framePosition.x}px`,
    top: `${framePosition.y}px`
  }
})

// 修改确认上传方法，添加防重复提交功能
const isUploading = ref(false)

// 计算完整的头像URL
const fullAvatarUrl = computed(() => {
  if (props.currentAvatar.startsWith('http')) {
    return props.currentAvatar
  } else {
    return `${baseURL}${props.currentAvatar}`
  }
})

// 触发文件选择对话框
const triggerFileInput = () => {
  fileInputRef.value.click()
}

// 处理文件选择变更
const handleFileChange = (event) => {
  const file = event.target.files[0]
  if (!file) return
  
  // 验证文件类型和大小
  const fileType = file.type
  if (fileType !== 'image/jpeg' && fileType !== 'image/png' && fileType !== 'image/bmp') {
    ElMessage.error('请上传JPG、PNG或BMP格式的图片')
    return
  }
  
  const maxSize = 5 * 1024 * 1024 // 5MB
  if (file.size > maxSize) {
    ElMessage.error('图片大小不能超过5MB')
    return
  }
  
  // 保存文件
  avatarFile.value = file
  
  // 创建预览
  const reader = new FileReader()
  reader.onload = e => {
    avatarPreview.value = e.target.result
    // 重置裁剪框
    resetCropFrame()
  }
  reader.readAsDataURL(file)
  
  // 重置文件输入
  event.target.value = ''
}

// 初始化裁剪
const initCrop = () => {
  nextTick(() => {
    if (!cropImageRef.value || !previewBoxRef.value) return
    
    // 重置裁剪框
    resetCropFrame()
    
    // 生成初始预览
    generateCropPreview()
  })
}

// 重置裁剪框
const resetCropFrame = () => {
  frameSize.value = 180 // 默认裁剪框大小
  
  // 居中裁剪框
  const box = previewBoxRef.value
  if (box) {
    framePosition.x = (box.clientWidth - frameSize.value) / 2
    framePosition.y = (box.clientHeight - frameSize.value) / 2
  }
}

// 开始拖动裁剪框
const startDragFrame = (event) => {
  if (dragInfo.isResizing) return
  event.preventDefault()
  
  // 只响应鼠标左键
  if (event.type === 'mousedown' && event.button !== 0) return
  
  dragInfo.isDragging = true
  
  // 记录起始位置
  dragInfo.startX = event.clientX || (event.touches && event.touches[0].clientX)
  dragInfo.startY = event.clientY || (event.touches && event.touches[0].clientY)
  dragInfo.startPosX = framePosition.x
  dragInfo.startPosY = framePosition.y
  
  // 添加事件监听
  document.addEventListener('mousemove', handleDragFrame)
  document.addEventListener('touchmove', handleDragFrame, { passive: false })
  document.addEventListener('mouseup', endDragFrame)
  document.addEventListener('touchend', endDragFrame)
}

// 处理裁剪框拖动
const handleDragFrame = (event) => {
  event.preventDefault()
  
  if (!dragInfo.isDragging) return
  
  // 获取当前位置
  const clientX = event.clientX || (event.touches && event.touches[0].clientX)
  const clientY = event.clientY || (event.touches && event.touches[0].clientY)
  
  // 计算拖动距离
  const deltaX = clientX - dragInfo.startX
  const deltaY = clientY - dragInfo.startY
  
  // 计算新位置
  let newX = dragInfo.startPosX + deltaX
  let newY = dragInfo.startPosY + deltaY
  
  // 限制框在图片范围内
  const box = previewBoxRef.value
  const img = cropImageRef.value
  if (box && img) {
    // 获取图片的实际显示尺寸和位置
    const imgRect = img.getBoundingClientRect()
    const boxRect = box.getBoundingClientRect()
    
    // 计算图片相对于容器的偏移
    const imgOffsetX = imgRect.left - boxRect.left
    const imgOffsetY = imgRect.top - boxRect.top
    
    // 限制裁剪框不超出图片边界
    newX = Math.max(imgOffsetX, Math.min(newX, imgOffsetX + imgRect.width - frameSize.value))
    newY = Math.max(imgOffsetY, Math.min(newY, imgOffsetY + imgRect.height - frameSize.value))
  }
  
  // 更新裁剪框位置
  framePosition.x = newX
  framePosition.y = newY
  
  // 实时生成预览
  generateCropPreview()
}

// 结束拖动
const endDragFrame = () => {
  dragInfo.isDragging = false
  
  // 移除事件监听
  document.removeEventListener('mousemove', handleDragFrame)
  document.removeEventListener('touchmove', handleDragFrame)
  document.removeEventListener('mouseup', endDragFrame)
  document.removeEventListener('touchend', endDragFrame)
  
  // 生成最终预览
  generateCropPreview()
}

// 开始调整大小
const startResize = (event) => {
  event.preventDefault()
  event.stopPropagation()
  
  // 只响应鼠标左键
  if (event.type === 'mousedown' && event.button !== 0) return
  
  dragInfo.isResizing = true
  
  // 记录起始位置和大小
  dragInfo.startX = event.clientX || (event.touches && event.touches[0].clientX)
  dragInfo.startY = event.clientY || (event.touches && event.touches[0].clientY)
  dragInfo.startSize = frameSize.value
  
  // 添加事件监听
  document.addEventListener('mousemove', handleResize)
  document.addEventListener('touchmove', handleResize, { passive: false })
  document.addEventListener('mouseup', endResize)
  document.addEventListener('touchend', endResize)
}

// 处理调整大小
const handleResize = (event) => {
  // 阻止默认行为
  event.preventDefault()
  
  if (!dragInfo.isResizing) return
  
  // 获取当前位置
  const clientX = event.clientX || (event.touches && event.touches[0].clientX)
  
  // 只关注X方向变化
  const deltaX = clientX - dragInfo.startX
  
  // 计算新大小，保持正方形，只关注宽度变化
  let newSize = dragInfo.startSize + deltaX
  
  // 限制最小尺寸，移除最大尺寸的固定限制
  newSize = Math.max(50, newSize)
  
  // 检查新大小是否超出图片边界
  const box = previewBoxRef.value
  const img = cropImageRef.value
  if (box && img) {
    const imgRect = img.getBoundingClientRect()
    const boxRect = box.getBoundingClientRect()
    
    // 计算图片相对于容器的偏移
    const imgOffsetX = imgRect.left - boxRect.left
    const imgOffsetY = imgRect.top - boxRect.top
    
    // 如果新大小会超出图片边界，则限制大小
    if (framePosition.x + newSize > imgOffsetX + imgRect.width ||
        framePosition.y + newSize > imgOffsetY + imgRect.height) {
      // 计算可能的最大尺寸
      const maxWidth = imgOffsetX + imgRect.width - framePosition.x
      const maxHeight = imgOffsetY + imgRect.height - framePosition.y
      // 取最小值以保持正方形
      newSize = Math.min(newSize, maxWidth, maxHeight)
    }
  }
  
  // 更新裁剪框大小
  frameSize.value = newSize
  
  // 实时生成预览
  generateCropPreview()
}

// 结束调整大小
const endResize = () => {
  dragInfo.isResizing = false
  
  // 移除事件监听
  document.removeEventListener('mousemove', handleResize)
  document.removeEventListener('touchmove', handleResize)
  document.removeEventListener('mouseup', endResize)
  document.removeEventListener('touchend', endResize)
  
  // 生成最终预览
  generateCropPreview()
}

// 生成裁剪预览 - 优化版本
const generateCropPreview = () => {
  if (!cropImageRef.value || !previewBoxRef.value) return
  
  const img = cropImageRef.value
  const box = previewBoxRef.value
  
  // 创建高质量canvas
  const canvas = document.createElement('canvas')
  const outputSize = 180 // 输出尺寸固定为180px
  canvas.width = outputSize
  canvas.height = outputSize
  
  const ctx = canvas.getContext('2d')
  
  // 禁用图像平滑，保持锐利边缘
  ctx.imageSmoothingEnabled = false
  
  // 清除画布
  ctx.clearRect(0, 0, canvas.width, canvas.height)
  
  // 获取图片的原始尺寸和显示尺寸
  const imgNaturalWidth = img.naturalWidth
  const imgNaturalHeight = img.naturalHeight
  const imgRect = img.getBoundingClientRect()
  const boxRect = box.getBoundingClientRect()
  
  // 计算显示比例
  const scaleX = imgNaturalWidth / imgRect.width
  const scaleY = imgNaturalHeight / imgRect.height
  
  // 计算裁剪框相对于图片的位置（精确到原图的像素）
  const cropX = Math.round((framePosition.x - (imgRect.left - boxRect.left)) * scaleX)
  const cropY = Math.round((framePosition.y - (imgRect.top - boxRect.top)) * scaleY)
  
  // 计算裁剪框在原图中的尺寸
  const cropWidth = Math.round(frameSize.value * scaleX)
  const cropHeight = Math.round(frameSize.value * scaleY)
  
  // 使用高质量绘制模式
  ctx.imageSmoothingEnabled = true
  ctx.imageSmoothingQuality = 'high'
  
  // 直接从原图裁剪到输出尺寸，避免中间步骤
  ctx.drawImage(
    img,
    cropX, cropY, cropWidth, cropHeight,
    0, 0, outputSize, outputSize
  )
  
  // 将裁剪后的图像设置为预览
  croppedPreview.value = canvas.toDataURL('image/png', 1.0) // 使用最高质量
  
  // 更新头像文件 - 使用高质量PNG格式
  canvas.toBlob((blob) => {
    if (blob) {
      avatarFile.value = new File([blob], 'avatar.png', { type: 'image/png' })
    }
  }, 'image/png', 1.0) // 最高质量
}

// 取消上传
const cancelUpload = () => {
  avatarFile.value = null
  avatarPreview.value = null
  croppedPreview.value = null
}

// 确认上传 - 触发事件让父组件处理
const confirmUpload = () => {
  if (!avatarFile.value || isUploading.value) return
  
  // 设置正在上传状态，防止重复点击
  isUploading.value = true
  
  // 发出更新事件，传递文件和预览URL
  emit('update', {
    file: avatarFile.value,
    previewUrl: croppedPreview.value
  })
  
  // 重置上传状态
  avatarFile.value = null
  avatarPreview.value = null
  croppedPreview.value = null
}

// 对外暴露方法
defineExpose({
  cancelUpload,
  triggerFileInput,
  // 暴露上传状态，供父组件使用
  isUploading
})
</script>

<template>
  <div class="avatar-page">
    <div class="avatar-upload-area">
      <el-button class="upload-btn" @click="triggerFileInput">
        上传头像
      </el-button>
      <span class="upload-info">支持jpg、png、bmp格式的图片，且文件小于5M</span>
      
      <input 
        ref="fileInputRef" 
        type="file" 
        style="display: none;" 
        accept="image/jpeg,image/png,image/bmp" 
        @change="handleFileChange"
      />
    </div>
    
    <div class="avatar-preview-area">
      <!-- 左侧裁剪区域：固定图片，移动框 -->
      <div class="main-preview">
        <div class="preview-box" ref="previewBoxRef">
          <!-- 空状态 - 更新为上传提示样式 -->
          <div v-if="!avatarPreview" class="empty-state">
            <div class="upload-icon">
              <i class="el-icon-upload"></i>
            </div>
            <p class="upload-text">选择一张本地的图片</p>
            <p class="upload-subtext">编辑后上传</p>
          </div>
          
          <!-- 裁剪区域 - 固定图片，移动和调整大小的框 -->
          <div v-if="avatarPreview" class="crop-container">
            <!-- 固定的背景图片 -->
            <img 
              ref="cropImageRef"
              :src="avatarPreview" 
              class="crop-image" 
              alt="裁剪区域"
              @load="initCrop"
            />
            
            <!-- 可移动和调整大小的裁剪框 -->
            <div 
              ref="cropFrameRef"
              class="movable-crop-frame" 
              :style="cropFrameStyle"
              @mousedown="startDragFrame"
              @touchstart="startDragFrame"
            >
              <!-- 调整大小的手柄 -->
              <div 
                class="resize-handle" 
                @mousedown.stop="startResize"
                @touchstart.stop="startResize"
              ></div>
            </div>
          </div>
        </div>
      </div>
      
      <!-- 右侧预览区域 -->
      <div class="size-preview">
        <h4 class="preview-title">头像预览</h4>
        
        <div class="large-preview">
          <div class="preview-image-container">
            <img 
              v-if="croppedPreview" 
              :src="croppedPreview" 
              alt="大尺寸预览"
            />
            <img 
              v-else 
              :src= fullAvatarUrl
              alt="大尺寸预览"
            />
          </div>
          <p>大尺寸头像 (180×180像素)</p>
        </div>
        
        <div class="small-preview">
          <div class="preview-image-container small">
            <img 
              v-if="croppedPreview" 
              :src="croppedPreview" 
              alt="小尺寸预览"
            />
            <img 
              v-else 
              :src="fullAvatarUrl" 
              alt="小尺寸预览"
            />
          </div>
          <p>小尺寸头像 (40×40像素)</p>
        </div>
        
        <div class="preview-actions" v-if="avatarFile">
          <el-button class="cancel-btn" @click="cancelUpload" :disabled="isUploading">取消</el-button>
          <el-button 
            type="primary" 
            class="netease-red-btn" 
            @click="confirmUpload" 
            :loading="isUploading"
            :disabled="isUploading">
            {{ isUploading ? '上传中...' : '确定' }}
          </el-button>
        </div>
      </div>
    </div>
  </div>
</template>

<style scoped>
.avatar-page {
  padding: 20px;
  display: flex;
  flex-direction: column;
  gap: 30px;
}

.avatar-upload-area {
  display: flex;
  align-items: center;
  gap: 15px;
  padding-bottom: 20px;
  border-bottom: 1px solid #ebeef5;
}

.upload-btn {
  background-color: #fff;
  border: 1px solid #dcdfe6;
  color: #333;
  padding: 6px 20px;
  font-size: 14px;
  border-radius: 4px;
}

.upload-btn:hover {
  border-color: #c0c4cc;
  color: #c20c0c;
}

.upload-info {
  color: #909399;
  font-size: 14px;
  margin-left: 10px;
}

.avatar-preview-area {
  display: flex;
  gap: 40px;
}

.main-preview {
  flex: 1;
}

.preview-box {
  position: relative;
  width: 400px;
  height: 400px;
  background-color: #fff;
  display: flex;
  justify-content: center;
  align-items: center;
  overflow: hidden;
  border-radius: 0;
  border: none;
}

.preview-image {
  max-width: 100%;
  max-height: 100%;
}

.crop-container {
  position: relative;
  width: 100%;
  height: 100%;
  overflow: hidden;
  background-color: #fff;
  display: flex;
  justify-content: center;
  align-items: center;
}

.crop-image {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  max-width: 100%;
  max-height: 100%;
}

.movable-crop-frame {
  position: absolute;
  border: 1px solid #fff;
  box-shadow: 0 0 0 9999px rgba(0, 0, 0, 0.5);
  cursor: move;
  box-sizing: border-box;
}

.resize-handle {
  position: absolute;
  width: 14px;
  height: 14px;
  right: -7px;
  bottom: -7px;
  background-color: #fff;
  border: 1px solid #ddd;
  border-radius: 50%;
  cursor: se-resize;
  z-index: 10;
}

.size-preview {
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
}

.preview-title {
  font-size: 14px;
  font-weight: normal;
  color: #333;
  margin: 0 0 15px 0;
}

.large-preview, .small-preview {
  display: flex;
  flex-direction: row;
  flex-wrap: wrap;
  align-content: stretch;
  justify-content: flex-start;
  align-items: center;
  margin-bottom: 15px;
}

.preview-image-container {
  width: 180px;
  height: 180px;
  background-color: #fff;
  display: flex;
  justify-content: center;
  align-items: center;
  overflow: hidden;
  margin-bottom: 8px;
}

.preview-image-container.small {
  width: 40px;
  height: 40px;
}

.preview-image-container img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.large-preview p, .small-preview p {
  color: #909399;
  font-size: 12px;
  margin: 0;
}

.preview-actions {
  margin-top: 20px;
  display: flex;
  gap: 10px;
  width: 100%;
  justify-content: center;
}

.cancel-btn {
  background-color: #f4f4f5;
  border-color: #dcdfe6;
  color: #606266;
}

.netease-red-btn {
  background-color: #c20c0c;
  border-color: #c20c0c;
}

.netease-red-btn:hover {
  background-color: #d33a3a;
  border-color: #d33a3a;
}


/* 添加空状态的新样式 */
.empty-state {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  width: 100%;
  height: 100%;
  background-color: #f5f5f5;
  color: #909399;
}

.upload-icon {
  font-size: 48px;
  margin-bottom: 15px;
  color: #dcdfe6;
}

.upload-icon i {
  display: inline-block;
  width: 60px;
  height: 60px;
  background-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="%23dcdfe6"><path d="M12 3L2 12h3v8h14v-8h3L12 3z"/></svg>');
  background-repeat: no-repeat;
  background-position: center;
}

.upload-text {
  font-size: 16px;
  color: #909399;
  margin: 5px 0;
}

.upload-subtext {
  font-size: 14px;
  color: #c0c4cc;
  margin: 0;
}

/* 响应式调整 */
@media (max-width: 768px) {
  .avatar-preview-area {
    flex-direction: column;
  }
  
  .preview-box {
    width: 100%;
    height: 300px;
  }
}
</style> 